#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#include "general.h"
#include "sudoku.h"
#include "solver.h"
#include "dlx.h"
#include "scheduler.h"

Statistics stat;

void gridSeedSparseMatrix (Grid g, SparseMatrix sm)
{
  int x, y, i;
  int sm_row;
  cell cur;
  int mask;

  for (y = 0; y < GRID_SIZE; y++)
    {
      for (x = 0; x < GRID_SIZE; x++)
	{
	  cur = gridIndex(g, x, y);
	  mask = 0x1;
	  for (i = 0; i < GRID_SIZE; i++)
	    {
	      if ((cur & mask) == 0)
		{
		  sm_row = candidateToRow(i+1, x, y);
		  removeRow(sm, sm_row);
		}
	      mask = mask << 1;
	    }
	}
    }
}

int main (int argc, char * argv[])
{
  char input[GRID_SIZE * GRID_SIZE + 1] = "12344321........";
    //"4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......";
    //"6.4..83.9...3.2.78.829..4.5.6..9..34...2.3...73..1..8.5.3..486.42.6.1...8.65..2..";
    //"..89.....3..4...2.25....19..17......4.......5......61..39....42.2...6..1.....85..";
    //".9.7..86..31..5.2.8.6........7.5...6...3.7...5...1.7........1.9.2.6..35..54..8.7.";
    //".................................................................................7.";
    //...................................................................................MLV...UOSC....N.W.X.....YHD.PSU..G...CL.I.D.B.......J.XLQP...E......I..FY...H.EC......T..RSO.JK...RLS.......W..G..D........N.V..RPT.FKM.......V.Y..AQEDG..N.HCU..K...F.TMO......I..B.Y.AH..E.U..A....PJ.G..DT..I..N.X.Q.YBE.....M.....V.....SAH....GU..L.BQ...RFP..O..M.J.HJRLPI...E....S..Q.U.O..V.H..O.C.F.U..G.RNE.A........S.A.PK...JVYO......U...CA.U..D....B.M.XY..N..F........O.LN.FQX.......M...EWPD.MXGB.I..OC.V......H..YTB.S....A....UC..L....PL.E.KU.W..O....SI.....YJ....ITVGD.C.NYR.K.....A.OX.F.VH.YN.JK.I.TAP.G.W..MNMUA..E...F.V.WJ...B..RGK";
  //"..LF..G.R.EX.JA..D.......B.S.M...J........RE.....A.......V....C.B..NL.PHY...P...BW..MLV...UOSC....N.W.X.....YHD.PSU..G...CL.I.D.B.......J.XLQP...E......I..FY...H.EC......T..RSO.JK...RLS.......W..G..D........N.V..RPT.FKM.......V.Y..AQEDG..N.HCU..K...F.TMO......I..B.Y.AH..E.U..A....PJ.G..DT..I..N.X.Q.YBE.....M.....V.....SAH....GU..L.BQ...RFP..O..M.J.HJRLPI...E....S..Q.U.O..V.H..O.C.F.U..G.RNE.A........S.A.PK...JVYO......U...CA.U..D....B.M.XY..N..F........O.LN.FQX.......M...EWPD.MXGB.I..OC.V......H..YTB.S....A....UC..L....PL.E.KU.W..O....SI.....YJ....ITVGD.C.NYR.K.....A.OX.F.VH.YN.JK.I.TAP.G.W..MNMUA..E...F.V.WJ...B..RGK";
    //"..LF..G.R.EX.JA..D.......B.S.M...J........RE.....A.......V....C.B..NL.PHY...P...BW..MLV...UOSC....N.W.X.....YHD.PSU..G...CL.I.D.B.......J.XLQP...E......I..FY...H.EC......T..RSO.JK...RLS.......W..G..D........N.V..RPT.FKM.......V.Y..AQEDG..N.HCU..K...F.TMO......I..B.Y.AH..E.U..A....PJ.G..DT..I..N.X.Q.YBE.....M.....V.....SAH....GU..L.BQ...RFP..O..M.J.HJRLPI...E....S..Q.U.O..V.H..O.C.F.U..G.RNE.A........S.A.PK...JVYO......U...CA.U..D....B.M.XY..N..F........O.LN.FQX.......M...EWPD.MXGB.I..OC.V......H..YTB.S....A....UC..L....PL.E.KU.W..O....SI.....YJ....ITVGD.C.NYR.K.....APOXOFQVHBYNRJKLIETAPDGUWSCMNMUACQELPOFSVDWJHXYBITRGK";
  //"CNLFYSGURPEXIJAMWDTHVKQOBBISHMLTCJKQGWONVYREPDUFXAUROGEDFVQAMTCKBXJNLIPHYSWAPKDTBWIXMLVYFHUOSCQJGENRWQXVJONEYHDRPSUFBGAKMCLTIRDCBFMKHTWSJUXLQPOGYEIVANMGINWFYBOUHDECKALJVXTQPRSOUJKHPIRLSVFMAQBEWNTGYCDXESQXAGJNCVWYRPTIFKMDOLBHUTVPYLXAQEDGBONIHCUSRKJWMFDTMOQCXWVNILKBJYRAHSFEGUPFAVWSUPJHGOMDTCEILBNRXKQYYBECNROKMTPQXUVDGFJWSAHILIXGUKYLSBQAEHRFPVTOCWMNJDHJRLPIDFAEYNGWSKMQXUCOTBVJHBMOVCTFYUWSGDRNEKAXPILQLFNSXARPKITCJVYOQHWMBDUEGVCAIUWQDSJKHBEMGXYPLNROFTKYTRGEHOULNPFQXSDBIJAVMWCQEWPDNMXGBRIALOCTVUFYSJKHGKYTBJSMIFXAQHPWUCROLNDVEPLDERKUAWCBOTMGNSIQVHFXYJSWHJITVGDXCUNYRLKMFEQBAPOXOFQVHBYNRJKLIETAPDGUWSCMNMUACQELPOFSVDWJHXYBITRGK";

  Grid grid;
  SparseMatrix sm;//, sm2, sm3;

#ifdef FIFO
  Fifo f[32];
#else
  Stack f[32];
#endif

  
  pthread_t threads[32];
  ProcArgs_T pargs[32];
  ProcStatus_T pstat;

  int i, j;

  grid = newGrid();
  popGrid(input, grid);
  //printf("puzzle\n");
  prtGrid(grid, 2);
  //printf("a1:\n");
  if (a1(grid))
    {
      printf("solved\n");
      prtGrid(grid, 2);
      return 0;
    }

  prtGrid(grid, 2);
  
  stat.enqueue_time = 0;
  stat.num_enqueue = 0;
  stat.malloc_time = 0;
  stat.dequeue_wait = 0;
  stat.dequeues = 0;
  stat.deq_avg = 0;
  for (i = 0; i < atoi(argv[1]); i++)
    {
      stat.dequeue_time[i] = 0;
      stat.num_dequeue[i] = 0;
      stat.processing_time[i] = 0;
      stat.schedule_overhead[i] = 0;
    }

  for (i = 0; i < 1; i++) 
    { 
      sm = newSparseMatrix(); 
      gridSeedSparseMatrix (grid, sm); 

      
      for (j = 0; j < 32; j++)
	{
#ifdef FIFO
	  f[j] = newFifo();
#else
	  f[j] = newStack();
#endif
	}
     
    
#ifdef SERIAL
      stat.start = rdtsc(); 
      dlx(sm);
      stat.stop = rdtsc();
      printf("\ntiming: %lld\n", stat.stop-stat.start); 
#else
      stat.start = rdtsc(); 
      pDlx(sm, f, atoi(argv[1]));
      launchProcessors(atoi(argv[1]), threads, &pstat, pargs, f); 
      collectProcessors(atoi(argv[1]), threads, &pstat);
      printf("\ntiming: %lld\n", stat.stop-stat.start); 
#endif


      for (j = 0; j < 32; j++)
	{
#ifdef FIFO
	  delFifo(f[j]); 
#else
	  delStack(f[j]); 
#endif
	}
      delSparseMatrix(sm); 
    } 
  delGrid(grid);

  printf("enqueue:      %lld %lld\n", stat.enqueue_time, stat.num_enqueue);
  printf("dequeue wait: %lld\n", stat.dequeue_wait);
  printf("dequeues:     %lld\n", stat.dequeues);
  printf("deq avg:      %lld\n", stat.deq_avg);
  printf("malloc :      %lld\n", stat.malloc_time);
  for (i = 0; i < atoi(argv[1]); i++)
    {
      printf("t:%d\t d%lld nd%lld p%lld s%lld\n", i, stat.dequeue_time[i], stat.num_dequeue[i], stat.processing_time[i], stat.schedule_overhead[i]);
    }


  return 0;  
}

